<?php


namespace app\app\controller;


use app\constant\ActivesConst;
use app\constant\BillConst;
use app\constant\DistriConst;
use app\constant\KanJiaConst;
use app\constant\OrderConst;
use app\constant\RewardConst;
use app\constant\WxUserConst;
use app\helper\OrderHelper;
use app\helper\RedisLock;
use app\helper\VipHelper;
use app\helper\WxHelper;
use app\libs\Utils;
use app\model\AdminActives;
use app\model\AdminActiveSku;
use app\model\AdminDistribution;
use app\model\AdminDistridetail;
use app\model\AdminDistrimoney;
use app\model\AdminKanjiaOrder;
use app\model\AdminOrder;
use app\model\AdminOrderItem;
use app\model\AdminReward;
use app\model\AppWxUser;
use app\util\Aes;
use app\util\ReturnCode;
use DateTime;
use EasyWeChat\Factory;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use Exception;
use think\Db;
use think\exception\DbException;
use think\facade\Log;

class Order extends Base
{
    const CREATE_ORDER_LOCK_KEY = 'create_order_lock_key_';

    //创建订单
    public function create()
    {
        $data = $this->request->post();
        //TODO 这里先写死，默认一次只能购买一个商品的一个sku
        $goodsInfo = $data['goods_info'][0];
        $userInfo = $data['user_info'];
        $useBalance = $data['use_balance'];//是否使用余额
        $orderType = $data['order_type'];//订单类型
        $kanJiaOrderId = null;//砍价订单id
        $invid = $this->request->param('invid');//推广的id
        $redisLock = new RedisLock ();
        $key = $this::CREATE_ORDER_LOCK_KEY . $goodsInfo['goods_id'] . '_' . $goodsInfo['sku_id'];
        try {
            Db::startTrans();
            //创建锁，key用通用前缀+商品id+skuid组成
            if (!$redisLock->lock($key, $expire = 3, $num = 1)) {
                throw new Exception('这次没抢到，再试一下吧！');
            }

            //订单创建步骤
            //----0检测用户信息----
            if (Utils::isEmpty($userInfo['user_name'])) {
                throw new Exception('姓名不能为空！');
            }
            if (!Utils::isMobile($userInfo['user_phone'])) {
                throw new Exception('手机号不正确！');
            }

            //----1检测商品状态----
            $goodsWhere = ['id' => $goodsInfo['goods_id'], 'status' => ActivesConst::STATUS_NORMAL, 'type' => $orderType];
            $goodsWhere = $this->addTid($goodsWhere);
            $goodsModel = AdminActives::get($goodsWhere);
            if (!$goodsModel) {
                throw new Exception('商品不存在或已过期');
            }

            //----2检测商品sku库存及限制数量----
            $skuWhere = ['aid' => $goodsInfo['goods_id'], 'id' => $goodsInfo['sku_id']];
            $goodsSkuModel = (new AdminActiveSku())->where($skuWhere)->where('stock', '>=', $goodsInfo['count'])->find();
            if (!$goodsSkuModel) {
                throw new Exception('商品库存不足');
            }

            //----3检测限购数量----
            $skuData = $goodsSkuModel->getData();
            $limitBuyCount = $skuData['limit_buy_count'];
            $checkLimitBuyCountWhere = ['sku_id' => $skuData['id']];
            // 未关闭的订单
            $sum = (new AdminOrderItem())->where($checkLimitBuyCountWhere)->where('status', '<>', OrderConst::ORDER_ITEM_STATUS_CLOSE)->sum('goods_num');
            if ($limitBuyCount != null && ($sum + $goodsInfo['count']) > $limitBuyCount) {
                throw new Exception('超过购买数量限制');
            }
            if ($orderType === ActivesConst::ACTIVE_TYPE_KJ) {
                $kanJiaOrderId = $data['kj_order_id'];//砍价订单id
                $kanJiaModel = AdminKanjiaOrder::get($kanJiaOrderId);
                if (!$kanJiaModel || $kanJiaModel->status == KanJiaConst::STATUS_CLOASE) {
                    throw new Exception('砍价订单不存在或已过期');
                }
                //判断一下砍价订单下是否还有关联的主订单处于未支付状态或已经支付了的，如果有，不允许重复创建订单
                $kjData = $kanJiaModel->getData();
                if ($kjData['order_id'] != null) {
                    $get = AdminOrder::get(['id' => $kanJiaModel->order_id,
                        'pay_status' => [OrderConst::PAY_STATUS_UN_PAY_ONLINE, OrderConst::PAY_STATUS_UN_PAY_OFFLINE, OrderConst::PAY_STATUS_PAID_ONLINE, OrderConst::PAY_STATUS_PAID_OFFLINE],
                        'trade_status' => [OrderConst::ORDER_STATUS_NORMAL, OrderConst::ORDER_STATUS_USED]
                    ]);
                    if ($get) {
                        throw new Exception('请不要重复下单');
                    }
                }
                $skuData['lowest_price'] = $kanJiaModel->current_price;
            }

            //----4检测优惠，计算金额 ----
            $userType = $this->userInfo['type'];
            $skuPrice = $skuData['lowest_price'];
            $orderAmount = $skuPrice * $goodsInfo['count'];//订单价
            if ($userType === WxUserConst::TYPE_VIP) {
                $skuPrice = $skuPrice - $skuData['vip_discount'];
                if ($skuPrice < 0) {
                    $skuPrice = 0;
                }
            }
            $totalAmount = $skuPrice * $goodsInfo['count'];//最终价

            //----5创建完成之后变更商品库存，若卖完则变更商品状态----

            $orderData = ['trade_status' => OrderConst::ORDER_STATUS_NORMAL];
            //...添加用户信息
            $orderData = ['uid' => $this->userInfo['uid'], 'user_name' => $userInfo['user_name'], 'user_phone' => $userInfo['user_phone']];
            $goodsData = $goodsModel->getData();

            //...添加收货信息
            if ($goodsData['transport_type'] === ActivesConst::TRANSPORT_TYPE_EXPRESS) {//如果是快递发货就要选地址
                //TODO 检测地址
            }

            //...添加支付信息
            $orderData = $this->addTid($orderData);
            if ($goodsData['pay_type'] === ActivesConst::PAY_TYPE_ONLINE) {
                $orderData['pay_status'] = OrderConst::PAY_STATUS_UN_PAY_ONLINE;
            } else {
                $orderData['pay_status'] = OrderConst::PAY_STATUS_UN_PAY_OFFLINE;
            }
            $orderData['order_amount'] = $orderAmount;
            //这里要判断是组支付还是余额支付还是微信支付
            $payAmount = (new OrderHelper())->dupPayWayOp([
                'useBalance' => $useBalance,
                'tid' => $this->getUserTid(),
                'uid' => $this->userInfo['uid'],
                'total_amount' => $totalAmount
            ]);
            $orderData['pay_amount'] = $payAmount;
            if ($payAmount == 0) {
                $orderData['pay_status'] = OrderConst::PAY_STATUS_PAID_ONLINE;
            }
            $orderData['total_amount'] = $totalAmount;

            //...添加备注
            $orderData['remark'] = $userInfo['remark'];

            //...生成订单号并生成订单
            $orderNo = OrderHelper::build_order_no();
            $orderData['id'] = $orderNo;
            if (!Utils::isEmpty($invid) && $this->userInfo['inv_code'] != $invid) {
                $orderData['invid'] = $invid;
            }
            $orderData['id'] = $orderNo;
            $orderData['goods_type'] = $goodsData['type'];
            $orderData['goods_id'] = $goodsData['id'];

            //......生成订单
            $orderCreatedModel = AdminOrder::create($orderData);
            if (!$orderCreatedModel) {
                throw new Exception('创建订单未成功');
            }

            //......生成订单详情
            $orderId = $orderNo;
            $orderItemData = ['order_id' => $orderId,
                'sid' => $goodsData['sid'],
                'sku_id' => $skuData['id'],
                'goods_id' => $goodsData['id'],
                'goods_num' => $goodsInfo['count'],
                'goods_price' => $skuData['lowest_price'],
                'discount_price' => $skuData['vip_discount'],
                'goods_amount' => $skuData['lowest_price'] * $goodsInfo['count'],
                'goods_title' => $goodsData['title'],
                'sku_title' => $skuData['title'],
                'sku_attach' => $skuData['attach'],
                'sku_reward' => $skuData['reward'] > 0 ? $skuData['reward'] : null,
                'goods_img' => $goodsData['banners'] != null ? json_decode($goodsData['banners'])[0] : null
            ];
            $orderItemData = $this->addTid($orderItemData);
            $orderItemModel = AdminOrderItem::create($orderItemData);
            if (!$orderItemModel) {
                throw new Exception('创建订单未成功');
            }

            //...如果是砍价订单，还需要去将砍价订单与此订单关联
            if ($orderType === ActivesConst::ACTIVE_TYPE_KJ) {
                $updateKanJai = AdminKanjiaOrder::update(['id' => $kanJiaOrderId, 'order_id' => $orderId, 'order_item_id' => $orderItemModel->id]);
                if (!$updateKanJai) {
                    throw new Exception('，关联砍价订单失败');
                }
            }

            //...修改库存,到这一步的时候还要再检查一次库存
            $skuModel = (new AdminActiveSku())->where($skuWhere)->where('stock', '>=', $goodsInfo['count'])->find();
            if (!$skuModel) {
                throw new Exception('，库存不足');
            }
            $decDone = $skuModel->setDec('stock', $goodsInfo['count']);
            $incDone = $skuModel->setInc('sales', $goodsInfo['count']);
            if (!$decDone || !$incDone) {
                throw new Exception('，库存异常');
            }

            //...因为库存有变化了，所以这里要去检测一下产品状态
            $skus = (new AdminActiveSku())->where(['aid' => $goodsData['id'], 'del' => 0])->where('stock', '>', 0)->select();//查询一下是否还有库存大于0的
            if (count($skus) === 0) {
                //如果没有了，就去更新主表
                $done = AdminActives::update(['id' => $goodsData['id'], 'status' => ActivesConst::STATUS_SOLD_OUT]);
                if (!$done) {
                    throw new Exception('，商品信息更新失败');
                }
            }
            $orderItemData = $orderItemModel->getData();
            //添加分销数据
            $distriMoneyMdoel = AdminDistrimoney::get($this->getUserTid(), null, true);
            if ($distriMoneyMdoel && $distriMoneyMdoel->on === 1) {
                //先判断是否有上级
                $where = ['uid' => $this->userInfo['uid']];
                $where = $this->addTid($where);
                $disModel = AdminDistribution::get($where);
                if ($disModel) {
                    //说明有分销关系，有的话就找到直接上线，目前只做一级分销
                    //获取分销比例
                    $prorated = $distriMoneyMdoel->p_first;


                    $money = (($orderItemData['goods_amount'] - $orderItemData['discount_price']) * ($prorated / 1000));
                    //只有金额大于等于一分钱的时候才记录
                    if ($money >= 1) {
                        $disData = ['uid' => $disModel->pid_1, 'order_id' => $orderId, 'order_item_id' => $orderItemData['id'], 'money' => $money, 'status' => DistriConst::STATUS_ORDER_CREATED];
                        $disData = $this->addTid($disData);
                        $disDone = AdminDistridetail::create($disData);
                        if (!$disDone) {
                            throw new Exception('，创建分销信息失败');
                        }
                    }
                }
            }
            // 添加推广赏金处理
            if (!Utils::isEmpty($invid) && $this->userInfo['inv_code'] != $invid && !Utils::isEmpty($orderItemData['sku_reward'])) {
                $appWxUser = AppWxUser::get(['inv_code' => $invid]);
                if ($appWxUser) {
                    $disData = ['uid' => $appWxUser->id, 'bought_uid' => $this->userInfo['uid'], 'order_id' => $orderId, 'order_item_id' => $orderItemData['id'], 'money' => $orderItemData['sku_reward'], 'status' => RewardConst::STATUS_ORDER_CREATED];
                    $disData = $this->addTid($disData);
                    $disDone = AdminReward::create($disData);
                    if (!$disDone) {
                        throw new Exception('，创建赏金信息失败');
                    }
                }
            }
            //----7发布延时消息，用于定时关闭未付款的订单，并恢复商品库存
            if ($goodsData['pay_type'] === ActivesConst::PAY_TYPE_ONLINE) {
                OrderHelper::pubCloseOrderQueue($orderId, 20);
            }
            if($orderType == ActivesConst::ACTIVE_TYPE_VIP && $orderData['pay_status'] ===OrderConst::PAY_STATUS_PAID_ONLINE){
                //如果是VIP订单并且订单状是已支付
                //这里处理续期
                $opVipOrderDone = $this->opVipOrder($this->userInfo['uid'],$skuData['attach']);
                if(!$opVipOrderDone){
                    throw new Exception('，处理续期失败');
                }
            }
            Db::commit();
            $redisLock->unlock($key);
            return $this->buildSuccess(['order_id' => $orderId, 'need_to_wxPay' => $payAmount == 0 ? false : true]);
        } catch (Exception $e) {
            $redisLock->unlock($key);
            Log::write('创建订单失败' . $e->getMessage(), 'error');
            Db::rollback();
            return $this->buildFailed(ReturnCode::FAILED, '下单失败' . $e->getMessage());
        }
    }

    /**
     * @param $uid
     * @param $attach
     * @return bool
     */
    private function opVipOrder($uid,$attach){
        return VipHelper::addVipTime($uid,((int)($attach))*60*60*24);
    }

    public function getOrderDetail()
    {
        $id = $this->request->param('order_id');
        if (!isset($id)) {
            return $this->buildFailed(ReturnCode::INVALID, '无效的id');
        } else {
            $model = AdminOrder::get($id);
            if ($model) {
                $orderItem = $model->item;
                $data = $model->getData();
                $data['items'] = $orderItem;
                if ($data['pay_status'] === OrderConst::PAY_STATUS_UN_PAY_ONLINE && $data['trade_status'] === OrderConst::ORDER_STATUS_NORMAL) {
                    try {
                        //双重保险，如果关闭订单的队列并没有执行，这里就去再再判断一下订单是否要关闭了，如果要关闭就去发一下消息
                        $endDate = new Datetime($data['create_time']);
                        $cDate = new DateTime();
                        if (($endDate->getTimestamp() + OrderConst::ORDER_AUTO_CLOSE_TIME) <= $cDate->getTimestamp()) {
                            OrderHelper::pubCloseOrderQueue($data['id'], 0);
                            $data['trade_status'] = OrderConst::ORDER_STATUS_CLOSE;
                        }
                    } catch (Exception $e) {
                    }
                }

                return $this->buildSuccess($data);
            }
        }
        return $this->buildFailed(ReturnCode::INVALID, '获取失败');
    }

    //用户核销信息
    public function getOrderUseCode()
    {
        $id = $this->request->param('order_id');
        if (!isset($id)) {
            return $this->buildFailed(ReturnCode::INVALID, '无效的id');
        } else {
            $model = AdminOrder::get($id);
            if ($model) {
                $data = $model->getData();
                if (OrderHelper::orderIsPaidAndNormal($data)) {
                    try {
                        $orderItem = (new AdminOrderItem())->where(['order_id' => $id])->select();
                        $key = config('wechat.USE_CODE_KEY');
                        $aes = new Aes($key);
                        foreach ($orderItem as $item) {
                            $useCode = $aes->encrypt($item['id'] . '');
                            if ($item['is_finish'] === OrderConst::ORDER_ITEM_UN_FINISH) {
                                $item['use_code'] = $useCode;
                            }
                            //这里换成每次生成核销码吧，避免日后被破解了算法，导致很多核销码出问题，日前的算法是通过对orderitemId进行aes加密
//                            $update = ['id' => $item['id']];
//                            $done = AdminOrderItem::update(['use_code' => $useCode], $update);
//                            if (!$done) {
//                                throw new Exception('生成核销码失败');
//                            }
                        }
                        $data['items'] = $orderItem;
                        return $this->buildSuccess($data);
                    } catch (Exception $e) {
                        return $this->buildFailed(ReturnCode::INVALID, '获取失败' . $e->getMessage());
                    }
                }

            }
        }
        return $this->buildFailed(ReturnCode::INVALID, '获取失败');

    }


    public function getOrderList()
    {
        $limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
        $start = $this->request->get('page', 1);
        $type = $this->request->get('type', '', 'intval');
        //这个接口只查询抢购的订单
        $where = ['goods_type' => [ActivesConst::ACTIVE_TYPE_QG, ActivesConst::ACTIVE_TYPE_QG_XS]];
        $where = $this->addTid($where);
        $where['uid'] = $this->userInfo['uid'];
        $obj = new AdminOrder();
        //订单类型 0 全部 1未付款 2待使用 3待收货 4待评价

        switch ($type) {
            case 1:
                $where['pay_status'] = OrderConst::PAY_STATUS_UN_PAY_ONLINE;
                $where['trade_status'] = OrderConst::ORDER_STATUS_NORMAL;
                break;
            case 2:
                $where['pay_status'] = OrderConst::PAY_STATUS_PAID_ONLINE;
                $where['trade_status'] = OrderConst::ORDER_STATUS_NORMAL;
                break;
            case 3:
                $where['pay_status'] = [OrderConst::PAY_STATUS_PAID_ONLINE, OrderConst::PAY_STATUS_UN_PAY_OFFLINE];//这个一般是发实物货的，所以有线上支付或线下货到付款支付两种
                $where['trade_status'] = OrderConst::ORDER_STATUS_NORMAL;
                $where['type'] = OrderConst::ORDER_TYPE_EXPRESS;
                break;
            case 4:
                $where['trade_status'] = OrderConst::ORDER_STATUS_USED;
                $where['has_comment'] = OrderConst::UN_COMMENT;
                break;
        }

//        $obj->where($where);
        try {
            $listObj = $obj->where($where)->order('create_time DESC')->paginate($limit, false, ['page' => $start])->each(function ($value, $key) {
                $value->item;
            })->toArray();
            return $this->buildSuccess([
                'list' => $listObj['data'],
                'count' => $listObj['total']
            ]);
        } catch (DbException $e) {
        }
        return $this->buildFailed(ReturnCode::FAILED, '获取失败');

    }

    /**
     * 发起退款
     * 退款操作流程：
     * 1、发起退款，区分退款类型，如果是退款到余额，则直接增加余额，如果是退到微信，则需要根据支付订单号发起退款
     *    其中退款到微信需要读取退款比例配置中的数据
     * 2、标记为退款中状态
     * 3、退款完成标记订单为已退款
     * 4、修改主订单及子订单交易状态为关闭
     * 5、涉及分销的要标识分销为关闭状态
     * 6、涉及佣金的要标识为关闭
     *
     */
    public function refund()
    {
        $helper = new OrderHelper();
        $result = $helper->applyRefund($this->request,$this->getUserTid(),$this->userInfo['uid']);
        if($result['code']==ReturnCode::SUCCESS){
            return $this->buildSuccess(null);
        }else{
            return $this->buildFailed($result['code'],$result['msg']);
        }
    }

    //获取退款信息
    public function getRefundData()
    {
        $orderId = $this->request->param('order_id');
        if (!$orderId) {
            return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
        }
        $where = [];
        $where = $this->addTid($where);
        $where['del'] = 0;
        $where['uid'] = $this->userInfo['uid'];
        $where['id'] = $orderId;
        $model = AdminOrder::get($where);
        if ($model) {
            $active = AdminActives::get($model->goods_id);
            $data = $model->getData();
            $data['refund_percentage'] = $active->refund_percentage;
            return $this->buildSuccess($data);
        } else {
            return $this->buildFailed(ReturnCode::FAILED, '获取失败');
        }
    }

}